/*>r6502lib.h
 *
 * BBC 6502 to RISC OS library code
 * by Michael Foot.
 * Version 1.01 - (31 Mar 2001).
 *
 */

/*#define __JMP_BUF_SIZE 100*/

/*#include <setjmp.h>*/
#include <stdio.h>
#include "kernel.h"
#include "swis.h"

extern void bbcvdu(char);
extern void getscreenaddress(void);
extern void osword(void);
extern void pushpsr(void);
extern void poppsr(void);
extern void r6502adc(int);
extern char r6502read(int);
extern void r6502sbc(int);
extern void r6502write(int,char);

extern _kernel_swi_regs regs;

extern char memory[0x10000];
extern char r6502_a;
extern char r6502_x;
extern char r6502_y;
extern char r6502_sp;
extern char r6502_ps;
extern int address;
extern char value, value2;
extern char nlo, nhi;

extern int loc_video_addr; /*screen address of local system*/
extern int bbc_video_mode; /*bbc video_mode*/
extern int bbc_video_addr; /*bbc video address*/

extern int quit, escape;

#define NFLAG 0x80
#define VFLAG 0x40
#define UFLAG 0x20
#define BFLAG 0x10
#define DFLAG 0x08
#define IFLAG 0x04
#define ZFLAG 0x02
#define CFLAG 0x01
#define NOTNFLAG 0x7F
#define NOTVFLAG 0xBF
#define NOTUFLAG 0xDF
#define NOTBFLAG 0xEF
#define NOTDFLAG 0xF7
#define NOTIFLAG 0xFB
#define NOTZFLAG 0xFD
#define NOTCFLAG 0xFE

#define STACK_START 0x100
#define STACK_END 0x1FF

#define AND &&
#define NOT !
#define OR ||
#define TRUE 0xFF
#define FALSE 0x00

#define STACK_PUSH(n) \
  memory[STACK_START+(r6502_sp--)] = n;

#define STACK_POP(n) \
  n = memory[STACK_START+(++r6502_sp)];

#define SETFLAG(nflag) \
  /*set bit*/ \
  r6502_ps = (r6502_ps | nflag);

#define CLEARFLAG(nflag) \
  /*set bit*/ \
  r6502_ps = (r6502_ps & ~nflag);

#define SETNFLAG(n) \
  /*clear bit 7 (N)*/ \
  r6502_ps = (r6502_ps & NOTNFLAG); \
  /*set bit 7 (N)*/ \
  r6502_ps = (r6502_ps | (n & NFLAG));

#define SETVFLAG(n) \
  /*clear bit 6 (V)*/ \
  r6502_ps = (r6502_ps & NOTVFLAG); \
  /*set bit 6 (V)*/ \
  r6502_ps = (r6502_ps | (n & VFLAG));

#define SETBFLAG(n) \
  /*clear bit 4 (B)*/ \
  r6502_ps = (r6502_ps & NOTBFLAG); \
  /*set bit 4 (B)*/ \
  r6502_ps = (r6502_ps | (n & BFLAG));

#define SETIFLAG(n) \
  /*clear bit 3 (I)*/ \
  r6502_ps = (r6502_ps & NOTIFLAG); \
  /*set bit 3 (I)*/ \
  r6502_ps = (r6502_ps | (n & IFLAG));

#define SETZFLAG(n) \
  if (n == 0) \
    /*set bit 1 (Z)*/ \
    r6502_ps = (r6502_ps | ZFLAG); \
  else \
    /*clear bit 1 (Z)*/ \
    r6502_ps = (r6502_ps & NOTZFLAG);

#define ADDRESSOFABSOLUTEX(n) \
  address = n+r6502_x;

#define ADDRESSOFABSOLUTEXPLUS(n) \
  address = n+r6502_x;

#define ADDRESSOFABSOLUTEYPLUS(n) \
  address = n+r6502_y;

#define ADDRESSOFPOSTINDEXEDY(n) \
  nlo = memory[n]; \
  value2 = ((n+1) & 0xFF); \
  nhi = memory[(n & 0xFF00) | value2]; \
  address = (nhi << 8) | nlo; \
  address += r6502_y;

#define OSBYTE \
  regs.r[0] = r6502_a; \
  regs.r[1] = r6502_x; \
  regs.r[2] = r6502_y; \
  _kernel_swi(OS_Byte,&regs,&regs); \
  r6502_x = regs.r[1]; \
  r6502_y = regs.r[2];

#define OSBYTE81 \
  regs.r[0] = r6502_a; \
  regs.r[1] = r6502_x; \
  regs.r[2] = r6502_y; \
  _kernel_swi(OS_Byte,&regs,&regs); \
  /*X is not corrupted on the BBC, like it is on RISC OS*/ \
  if (regs.r[1] != 0xFF) \
    r6502_x = regs.r[1]; \
  r6502_y = regs.r[2];

#define OSWORD \
  osword();

#define OSWRCH \
  regs.r[0] = r6502_a; \
  _kernel_swi(OS_WriteC,&regs,&regs);

#define WAIT_FOR_VERTICAL_SYNC \
  regs.r[0] = 0x13; \
  _kernel_swi(OS_Byte,&regs,&regs); \

#define ADCxx(n) \
  r6502adc(n);

#define ADC_ABSOL(n) \
  value = r6502read(n); \
  r6502adc(value);

#define ADC_IMMED(n) \
  r6502adc(n);

#define ADC_POSTI(n) \
  ADDRESSOFPOSTINDEXEDY(n) \
  value = r6502read(address); \
  r6502adc(value);

#define ADC_ZEROP(n) \
  value = memory[n]; \
  r6502adc(value);

#define AND_IMMED(n) \
  r6502_a &= n; \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define BCC(n) \
  if (!(r6502_ps & CFLAG)) \
    goto n;

#define BCS(n) \
  if (r6502_ps & CFLAG) \
    goto n;

#define BEQ(n) \
  if (r6502_ps & ZFLAG) \
    goto n;

#define BNE(n) \
  if (!(r6502_ps & ZFLAG)) \
    goto n;

#define CLC \
  CLEARFLAG(CFLAG);

#define CLD \
  CLEARFLAG(DFLAG);

#define CMP_ABSOL(n) \
  value = r6502read(n); \
  value2 = (r6502_a-value); \
  if (r6502_a >= value) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  SETNFLAG(value2) \
  SETZFLAG(value2)

#define CMP_ABSXP(n) \
  ADDRESSOFABSOLUTEXPLUS(n) \
  value = r6502read(address); \
  value2 = (r6502_a-value); \
  if (r6502_a >= value) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  SETNFLAG(value2) \
  SETZFLAG(value2)

#define CMP_IMMED(n) \
  value2 = (r6502_a-n); \
  if (r6502_a >= n) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  SETNFLAG(value2) \
  SETZFLAG(value2)

#define CPX_IMMED(n) \
  value2 = (r6502_x-n); \
  if (r6502_x >= n) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  SETNFLAG(value2) \
  SETZFLAG(value2)

#define CPY_IMMED(n) \
  value2 = (r6502_y-n); \
  if (r6502_y >= n) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  SETNFLAG(value2) \
  SETZFLAG(value2)

#define DEC_ABSOL(n) \
  value = r6502read(n); \
  value--; \
  r6502write(n,value); \
  SETNFLAG(value) \
  SETZFLAG(value)

#define DEC_ZEROP(n) \
  value = memory[n]; \
  value--; \
  memory[n] = value; \
  SETNFLAG(value) \
  SETZFLAG(value)

#define DEX \
  r6502_x--; \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define DEY \
  r6502_y--; \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define INC_ABSOL(n) \
  value = r6502read(n); \
  value++; \
  r6502write(n,value); \
  SETNFLAG(value) \
  SETZFLAG(value)

#define INC_ABSOX(n) \
  ADDRESSOFABSOLUTEX(n) \
  value = r6502read(address); \
  value++; \
  r6502write(address,value); \
  SETZFLAG(value) \
  SETNFLAG(value)

#define INC_ZEROP(n) \
  value = memory[n]; \
  value++; \
  memory[n] = value; \
  SETNFLAG(value) \
  SETZFLAG(value)

#define INX \
  r6502_x++; \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define INY \
  r6502_y++; \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define JMP_ABSOL(n) \
  goto n;

#define JSR_ABSOL(n, l) \
  r6502jsr(n); \
  pushpsr(); \
  goto l;

#define JSR_ABSOLO(n) \
  n();

#define LDA_ABSOL(n) \
  r6502_a = r6502read(n); \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDA_ABSXP(n) \
  ADDRESSOFABSOLUTEXPLUS(n) \
  r6502_a = r6502read(address); \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDA_ABSYP(n) \
  ADDRESSOFABSOLUTEYPLUS(n) \
  r6502_a = r6502read(address); \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDA_IMMED(n) \
  r6502_a = n; \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDA_POSTI(n) \
  ADDRESSOFPOSTINDEXEDY(n) \
  r6502_a = r6502read(address); \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDA_ZEROP(n) \
  r6502_a = memory[n]; \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define LDX_ABSOL(n) \
  r6502_x = r6502read(n); \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define LDX_IMMED(n) \
  r6502_x = n; \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define LDX_ZEROP(n) \
  r6502_x = memory[n]; \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define LDY_ABSOL(n) \
  r6502_y = r6502read(n); \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define LDY_ABSXP(n) \
  ADDRESSOFABSOLUTEXPLUS(n) \
  r6502_y = r6502read(address); \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define LDY_IMMED(n) \
  r6502_y = n; \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define LDY_ZEROP(n) \
  r6502_y = memory[n]; \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define LSR_ABSOL(n) \
  value = r6502read(n); \
  if (value & 0x01) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  value = (value >> 1); \
  r6502write(n,value); \
  CLEARFLAG(NFLAG) \
  SETZFLAG(value)

#define LSR_ABSXP(n) \
  ADDRESSOFABSOLUTEXPLUS(n) \
  value = r6502read(address); \
  if (value & 0x01) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  value = (value >> 1); \
  r6502write(address,value); \
  CLEARFLAG(NFLAG) \
  SETZFLAG(value)

#define PHA \
  STACK_PUSH(r6502_a)

#define PLA \
  STACK_POP(r6502_a) \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define RLA_ABSOL(n) \
  value = (r6502_ps & CFLAG); \
  value2 = r6502read(n); \
  if (value2 & 0x80) \
    SETFLAG(CFLAG) \
  else \
    CLEARFLAG(CFLAG) \
  value2 = (value2 << 1); \
  if (value) \
    value2 |= 1; \
  r6502write(n,value2); \
  r6502_a &= value2; \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define RTS \
  STACK_POP(nlo); \
  STACK_POP(nhi); \
  poppsr();
  /*return(0);*/
  /*longjump(jmpbuffer,value);*/
  /*r6502rts();*/

#define SBCxx(n) \
  r6502sbc(n);

#define SBC_ABSOL(n) \
  value = r6502read(n); \
  r6502sbc(value);

#define SBC_ABSXP(n) \
  ADDRESSOFABSOLUTEXPLUS(n) \
  value = r6502read(address); \
  r6502sbc(value);

#define SBC_ABSYP(n) \
  ADDRESSOFABSOLUTEYPLUS(n) \
  value = r6502read(address); \
  r6502sbc(value);

#define SBC_IMMED(n) \
  r6502sbc(n);

#define SBC_POSI(n) \
  ADDRESSOFPOSTINDEXEDY(n) \
  value = r6502read(address); \
  r6502sbc(value);

#define SBC_ZEROP(n) \
  value = memory[n]; \
  r6502sbc(value);

#define SEC \
  SETFLAG(CFLAG);

#define STA_ABSOL(n) \
   r6502write(n,r6502_a);

#define STA_ABSOX(n) \
   ADDRESSOFABSOLUTEX(n) \
   r6502write(address,r6502_a);

#define STA_POSTI(n) \
  ADDRESSOFPOSTINDEXEDY(n) \
  r6502write(address,r6502_a);

#define STA_ZEROP(n) \
  memory[n] = r6502_a;

#define STX_ABSOL(n) \
   r6502write(n,r6502_x);

#define STX_ZEROP(n) \
  memory[n] = r6502_x;

#define STY_ABSOL(n) \
   r6502write(n,r6502_y);

#define TAX \
  r6502_x = r6502_a; \
  SETNFLAG(r6502_x) \
  SETZFLAG(r6502_x)

#define TAY \
  r6502_y = r6502_a; \
  SETNFLAG(r6502_y) \
  SETZFLAG(r6502_y)

#define TXA \
  r6502_a = r6502_x; \
  SETNFLAG(r6502_a) \
  SETZFLAG(r6502_a)

#define TYA \
  r6502_a = r6502_y; \
  SETZFLAG(r6502_a) \
  SETNFLAG(r6502_a)
